﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;
using JTLeigh.Commerce.Spencer.Core.Common;

namespace JTLeigh.Commerce.Spencer.Core.Service
{

	/// <summary>
	/// WCF instance provider used in conjunction with <see cref="DependencyInjectionServiceBehaviorAttribute"/>
	/// to perform dependency injection on WCF services.
	/// </summary>
	/// <remarks>
	/// <para>
	/// <see cref="DependencyInjectionInstanceProvider"/> uses the supplied dependency injection 
	/// container to resolve the service type.
	/// </para>
	/// </remarks>
	public sealed class DependencyInjectionInstanceProvider : IInstanceProvider
	{

		#region Fields

		private IUnityContainer _container;
		private Type _serviceType;

		#endregion // Fields

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="DependencyInjectionInstanceProvider"/> 
		/// with the specified dependency injection container and service type.
		/// </summary>
		/// <param name="container">The dependency injection container to use to resolve the 
		/// service.</param>
		/// <param name="serviceType">The service type.</param>
		public DependencyInjectionInstanceProvider(IUnityContainer container, Type serviceType)
		{
			Safety.AssertArgumentNotNull("container", container);
			Safety.AssertArgumentNotNull("serviceType", serviceType);

			_container = container;
			_serviceType = serviceType;
		}

		#endregion // Constructors

		#region IInstanceProvider Members

		/// <summary>
		/// Gets an instance of the service type.
		/// </summary>
		/// <param name="instanceContext">Ignored.</param>
		/// <returns>An instance of the service type with its dependencies injected.</returns>
		public object GetInstance(InstanceContext instanceContext)
		{
			// instanceContext can be null.

			return _container.Resolve(_serviceType);
		}

		/// <summary>
		/// Gets an instance of the service type.
		/// </summary>
		/// <param name="instanceContext">Ignored.</param>
		/// <param name="message">Ignored.</param>
		/// <returns>An instance of the service type with its dependencies injected.</returns>
		public object GetInstance(InstanceContext instanceContext, Message message)
		{
			// instanceContext can be null.
			// message can be null.

			return _container.Resolve(_serviceType);
		}

		/// <summary>
		/// Does nothing.
		/// </summary>
		/// <param name="instanceContext">Ignored.</param>
		/// <param name="instance">Ignored.</param>
		public void ReleaseInstance(InstanceContext instanceContext, object instance)
		{
		}

		#endregion // IInstanceProvider Members

	}

}
